package com.ning.parking.domain.VO;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.ning.parking.domain.dto.PageBase;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author ChenN
 * @Date 2025/3/12 11:12
 * @Version 0.0.1
 **/
@Setter
@Getter
@NoArgsConstructor
@ToString
public class Pagination<T> extends PageBase {
    private static final long serialVersionUID = 1L;
    /**
     * 总记录数
     */
    private long total;
    /**
     * 总页数
     */
    private long totalPage;

    /**
     * 列表数据
     */
    private List<T> records = new ArrayList<>();

    /**
     * 分页
     *
     * @param records  列表数据
     * @param total    总记录数
     * @param pageSize 每页记录数
     * @param pageNo   当前页数
     */
    public Pagination(List<T> records, long total, long pageNo, long pageSize) {
        this.records = records;
        this.total = total;
        this.pageNo = pageNo;
        this.pageSize = pageSize;
        this.totalPage = (long) Math.ceil((double) total / pageSize);
    }

    public static <T> Pagination<T> empty() {
        final Pagination<T> pagination = new Pagination<>();
        pagination.records = new ArrayList<>();
        pagination.total = 0L;
        pagination.pageNo = 1L;
        pagination.pageSize = 10L;
        return pagination;
    }

    public static <T> Pagination<T> empty(PageBase pageBase) {
        final Pagination<T> pagination = new Pagination<>();
        pagination.records = new ArrayList<>();
        pagination.total = 0L;
        pagination.pageNo = pageBase.getPageNo();
        pagination.pageSize = pageBase.getPageSize();
        return pagination;
    }

    public Pagination(IPage<T> page) {
        this.records = page.getRecords();
        this.total = page.getTotal();
        this.pageNo = page.getCurrent();
        this.pageSize = page.getSize();
        this.totalPage = page.getPages();
    }

    public static <T> Pagination<T> of(List<T> records, long total, long pageNo, long pageSize) {
        final Pagination<T> pagination = new Pagination<>();
        pagination.records = records;
        pagination.total = total;
        pagination.pageNo = pageNo;
        pagination.pageSize = pageSize;
        pagination.totalPage = (long) Math.ceil((double) total / pageSize);
        return pagination;
    }

    public static <T> Pagination<T> of(Collection<T> records, long total, long pageNo, long pageSize) {
        final Pagination<T> pagination = new Pagination<>();
        pagination.records = new ArrayList<>(records);
        pagination.total = total;
        pagination.pageNo = pageNo;
        pagination.pageSize = pageSize;
        pagination.totalPage = (long) Math.ceil((double) total / pageSize);
        return pagination;
    }

    public static <T> Pagination<T> of(IPage<T> page) {
        final Pagination<T> pagination = new Pagination<>();
        pagination.records = page.getRecords();
        pagination.total = page.getTotal();
        pagination.pageNo = page.getCurrent();
        pagination.pageSize = page.getSize();
        pagination.totalPage = page.getPages();
        return pagination;
    }

    public static <T, R> Pagination<R> of(IPage<T> page, Function<T, R> function) {
        final Pagination<R> pagination = new Pagination<>();
        pagination.total = page.getTotal();
        pagination.pageNo = page.getCurrent();
        pagination.pageSize = page.getSize();
        pagination.totalPage = page.getPages();
        if (CollectionUtils.isNotEmpty(page.getRecords())) {
            pagination.records = page.getRecords().stream().map(function).collect(Collectors.toList());
        }
        return pagination;
    }


    public static <T, R> Pagination<R> of(IPage<T> page, List<R> records) {
        final Pagination<R> pagination = new Pagination<>();
        pagination.records = records;
        pagination.total = page.getTotal();
        pagination.pageNo = page.getCurrent();
        pagination.pageSize = page.getSize();
        pagination.totalPage = page.getPages();
        return pagination;
    }


    public static <T, R> Pagination<R> of(Pagination<T> page, List<R> records) {
        final Pagination<R> pagination = new Pagination<>();
        pagination.records = records;
        pagination.total = page.getTotal();
        pagination.pageNo = page.getPageNo();
        pagination.pageSize = page.getPageSize();
        pagination.totalPage = page.getTotalPage();
        return pagination;
    }


    public static <T, R> Pagination<R> of(Pagination<T> page, Function<T, R> function) {
        final Pagination<R> pagination = new Pagination<>();
        pagination.total = page.getTotal();
        pagination.pageNo = page.getPageNo();
        pagination.pageSize = page.getPageSize();
        pagination.totalPage = page.getTotalPage();
        if (CollectionUtils.isNotEmpty(page.getRecords())) {
            pagination.records = page.getRecords().stream().map(function).collect(Collectors.toList());
        }
        return pagination;
    }
}
